
Cromossom::Cromossom(int k, int L, Set* sets) {
	this->k = k;
	this->L = L;
	this->sets = sets;
	solution_as_set = NULL;
	
	solution = randomInit();
	fitness = calculateFitness(solution);
	calculateSolutionAsSet();
}

	
Cromossom::~Cromossom(){
	delete solution;
	delete solution_as_set;
}


int* Cromossom::randomInit() {
	int index[L];
	for( int i = 0; i < L; ++i ) {
		index[i] = i;
	}
	
	for( int i = 0; i < L; ++i ) {
		swap( &index[i], &index[rand()%L] );
	}
	
	int *init_solution = new int[k];
	
	for( int i = 0; i < k; ++i ) {
		init_solution[i] = index[i];
	}
	
	return init_solution;
}

int Cromossom::calculateFitness(int* s) {
	
	Set temp;
	temp.union_(&sets[s[0]]);
	
	for( int i = 1; i < k; ++i )
		temp.intersection(&sets[s[i]]);
	
	return temp.cardinality();
}

void Cromossom::applyTranspossom() {
	VNS(solution);
	if (!isValid(solution)) {
		cout << "Invalid solution after apply transpossom." << endl;
		exit(-1);
	}
}

void Cromossom::applyPlasmideo(Set* plasmideo) {
	if (plasmideo == NULL) {
		return;
	}
	
	int* plasmideo_array = plasmideo->getArray();

	for (int i = 0; i < plasmideo->cardinality(); ++i) {
		if (!isInCromossom(plasmideo_array[i])) {
			solution[rand()%k] = plasmideo_array[i];
		}
	}
	
	delete [] plasmideo_array;
	
	fitness = calculateFitness(solution);
	calculateSolutionAsSet();
}

bool Cromossom::isInCromossom(int x) {
	for (int i = 0; i < k; ++i) {
		if (solution[i] == x) {
			return true;
		}
	}
	return false;
}

int Cromossom::assessFitness() {
	return fitness;
}

Set* Cromossom::getSolutionAsSet() {
	return solution_as_set;
}

void Cromossom::calculateSolutionAsSet(){
	
	delete solution_as_set;
	
	solution_as_set = new Set();
	
	for(int i = 0; i < k; ++i) {
		solution_as_set->insert(solution[i]);
	}
}

void Cromossom::VNS(int* S) {
	int* ret = new int[k];
	copySolution(ret,S);
	int quality_ret = calculateFitness(ret);
	
	for(int i = 1; i <= k; ++i ) {
		int* new_solution = changeN(S, i);
		
		int quality_new_solution = calculateFitness(new_solution);
		
		if(quality_new_solution > quality_ret) {
			copySolution(ret,new_solution);
			quality_ret = quality_new_solution;
			i = 0;
		}
		delete [] new_solution;
	}
	copySolution(S,ret);
	fitness = quality_ret;
	
	delete [] ret;
}

int* Cromossom::changeN(int* S, int n) {
	
	int is_in_solution[L];
	memset(is_in_solution,0,L*sizeof(int));
	
	for( int i = 0; i < k; ++i )
		is_in_solution[S[i]] = 1;
	
	int* new_solution = new int[k];
	
	int changes[k];
	for(int i = 0; i < k; ++i) {
		changes[i] = i;
		new_solution[i] = S[i];
	}
	
	for(int i = 0; i < k; ++i)
		swap(&changes[i], &changes[rand()%k]);
	
	int set_to_be_inserted;
	for(int i = 0; i < n; ++i) {
		int set_to_be_inserted;
		
		int sets_to_be_inserted[L];
		for(int l = 0; l < L; ++l)
			sets_to_be_inserted[l] = l;
		
		for(int l = 0; l < L; ++l)
			swap(&sets_to_be_inserted[l], &sets_to_be_inserted[rand()%L]);
		
		for(int l = 0; l < L; ++l) {
			if(!is_in_solution[sets_to_be_inserted[l]]) {
				set_to_be_inserted = sets_to_be_inserted[l];
				break;
			}
		}

		is_in_solution[new_solution[changes[i]]] = 0;
		new_solution[changes[i]] = set_to_be_inserted;
		is_in_solution[new_solution[changes[i]]] = 1;
	}
	
	return new_solution;
}

void Cromossom::copySolution(int* s1, int* s2) {
	for( int i = 0; i < k; ++i )
		s1[i] = s2[i];
}

bool Cromossom::isValid(int* s){
	for (int i = 0; i < k; ++i) {
		for (int j = i+1; j < k; ++j) {
			if(s[i] == s[j]) {
				return false;
			}
		}
	}
	return true;
}


